package org.ihelpuoo.parser.sql;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.ihelpuoo.db.sql.SQLUtils;
import org.ihelpuoo.lang.ArrayUtils;
import org.ihelpuoo.lang.LoaderException;
import org.ihelpuoo.lang.RenderException;
import org.ihelpuoo.lang.StringUtils;
import org.ihelpuoo.parser.AbstractTextEngine;

public class TableFieldsParser extends AbstractTextEngine implements ITableFields
{

	private List<IField>	fields;
	private String[]		pks;
	private String[]		uks;
	private String			_s;

	public void parse(Reader r) throws LoaderException
	{
		try
		{
			List<FieldParser> fs = new LinkedList<FieldParser>();
			StringBuffer sb = new StringBuffer();
			StringBuffer b = new StringBuffer();
			int c;
			boolean isIn = false;
			while (true)
			{
				c = r.read();
				if (c != -1)
					b.append((char)c);
				if (c == (int)'(')
				{
					isIn = true;
					sb.append((char)c);
				}
				else if (c == (int)')')
				{
					isIn = false;
					sb.append((char)c);
				}
				else if ((c == (int)',' && !isIn) || c == -1)
				{
					String s = StringUtils.trim(sb.toString());
					if (s.length() == 0)
					{
						throw new LoaderException("Field is empty or start by ','");
					}
					if (s.startsWith("PRIMARY KEY"))
					{
						pks = retrieveKeyFields(s);
					}
					else if (s.startsWith("UNIQUE KEY"))
					{
						uks = retrieveKeyFields(s);
					}
					else if (s.startsWith("KEY"))
					{
					}
					else
					{
						FieldParser fp = new FieldParser();
						fp.parse(s);
						fp.validate();
						fs.add(fp);
					}
					if (c == -1)
						break;
					sb = new StringBuffer();
				}
				else
				{
					sb.append((char)c);
				}
			}
			_s = b.toString();
			fields = new ArrayList<IField>(fs.size());
			Iterator<FieldParser> it = fs.iterator();
			while (it.hasNext())
			{
				FieldParser f = (FieldParser)it.next();
				if (ArrayUtils.isInArray(pks,f.getName()))
					f.setPrimaryKey(true);
				if (ArrayUtils.isInArray(uks,f.getName()))
					f.setUnique(true);
				f.validate();
				fields.add(f);
			}
		}
		catch (IOException e)
		{
			throw LoaderException.wrap(e);
		}
	}

	private String[] retrieveKeyFields(String s) throws LoaderException
	{
		String[] keys;
		int b = s.indexOf('(');
		int e = s.lastIndexOf(')');
		if (b == -1 || e == -1)
		{
			throw new LoaderException("Error KEY defination: \"" + s + "\"");
		}
		String ss = s.substring(b + 1,e);
		keys = ss.split("[,]");
		for (int i = 0; i < keys.length; i++)
			keys[i] = SQLUtils.formatName(keys[i]);
		return keys;
	}

	public void render2(Writer w) throws RenderException
	{
		try
		{
			w.append(_s);
		}
		catch (IOException e)
		{
			throw new RenderException(e);
		}
	}

	@Override
	public String toString()
	{
		return _s;
	}

	public IField fieldAt(int index)
	{
		return fields.get(index);
	}

	public List<IField> fields()
	{
		return fields;
	}

	public int length()
	{
		return fields.size();
	}

}
